
#include "mb_coils.h"
#include "mb_adu.h"
#include "mb_comm.h"
#include "mb_crc.h"
#include "mb_datamodel.h"
#include "mb_debug.h"
#include "mb_functioncode.h"

//--------------------------------------------从站--------------------------------------------------//

/**
 * @brief 01 读线圈功能码 响应
 * @param hslave        从站指针
 * @param pSrc          需要解析的数据指针
 * @ret   MB_OK 成功 其它 出错
*/
MB_StatusTypeDef MB_COILS_Read_Response(
    MB_SLAVE_HandleTypeDef *hslave,
    uint8_t *pReqbuf,
    uint8_t *pRspbuf,
    uint16_t *pRsplen)
{
    uint16_t rspDataLen = 0;
    uint16_t rspBufLen = 0;
    uint16_t crc = 0;

    MB_READ_REQADU_HandleTypeDef *pReqADU = (MB_READ_REQADU_HandleTypeDef *)pReqbuf;
    MB_READ_RSPADU_HandleTypeDef *pRspADU = (MB_READ_RSPADU_HandleTypeDef *)pRspbuf;
    //判断线圈数量是不是 < 2000 (GB/T 1958.2.1 2008  第十二页)
    if (MB_PP_NTOHS(pReqADU->Pdu.Quantity) < 0x7d0 && MB_PP_NTOHS(pReqADU->Pdu.Quantity) >= 1) //2000
    {
        //判断开始地址加上长度是不是在定义的寄存器范围内
        if (MB_PP_NTOHS(pReqADU->Pdu.StartAddress) + MB_PP_NTOHS(pReqADU->Pdu.Quantity) < hslave->Regedit.CoilsBufSize)
        {
            //处理请求
            pRspADU->AdditionalAddress = hslave->SlaveID;
            pRspADU->Pdu.FunctionCode = MB_FUN_READ_COILS;
            //从内存中读取线圈
            if (MB_BitArrayToByteArray(
                    hslave->Regedit.pCoilsBuffPtr,
                    MB_PP_NTOHS(pReqADU->Pdu.StartAddress),
                    MB_PP_NTOHS(pReqADU->Pdu.Quantity),
                    pRspADU->Pdu.Data,
                    &rspDataLen) == MB_OK)
            {
                //计算长度
                pRspADU->Pdu.ByteCount = rspDataLen;
                rspBufLen = rspDataLen + 3;
                crc = MB_GenerateCRC16CheckCode(pRspbuf, rspBufLen);
                pRspADU->Pdu.Data[rspDataLen ] = (crc & 0xff00) >> 8;  
                pRspADU->Pdu.Data[rspDataLen + 1] = (crc & 0x00ff);
               *pRsplen = rspBufLen + 2;
								return MB_OK;
            }
            else
            {
                return MB_SLAVE_ExceptionRsp(hslave, pReqADU->Pdu.FunctionCode, 4, pRspbuf, pRsplen);
            }
        }
        else
        {
            return MB_SLAVE_ExceptionRsp(hslave, pReqADU->Pdu.FunctionCode, 2, pRspbuf, pRsplen);
        }
    }
    else
    {
        return MB_SLAVE_ExceptionRsp(hslave, pReqADU->Pdu.FunctionCode, 3, pRspbuf, pRsplen);
    }	
}

/**
 * @brief 05 写单个线圈功能码 响应
 * @param hslave        从站指针
 * @param pSrc          需要解析的数据指针
 * @ret   MB_OK 成功 其它 出错
*/
MB_StatusTypeDef MB_COILS_WriteSingle_Response(
    MB_SLAVE_HandleTypeDef *hslave,
    uint8_t *pReqBuf,
    uint8_t *pRspBuf,
    uint16_t *pRspLen)
{
    uint16_t rspDataLen = 0;
    uint16_t crc = 0;

    MB_WRITE_SINGLE_REQADU_HandleTypeDef *pReqADU = (MB_WRITE_SINGLE_REQADU_HandleTypeDef *)pReqBuf;
    MB_WRITE_SINGLE_RSPADU_HandleTypeDef *pRspADU = (MB_WRITE_SINGLE_RSPADU_HandleTypeDef *)pRspBuf;
    //判断值是不是 0X0000 / 0XFF00 (GB/T 1958.2.1 2008  第十九页)
    if (pReqADU->Pdu.Value == 0x0000 || pReqADU->Pdu.Value == 0x00FF)
    {
        //判断开始地址加上长度是不是在定义的寄存器范围内
        if (MB_PP_NTOHS(pReqADU->Pdu.StartAddress) < hslave->Regedit.CoilsBufSize)
        {
            //处理请求
            pRspADU->AdditionalAddress = hslave->SlaveID;
            pRspADU->Pdu.FunctionCode = MB_FUN_WRITE_SINGLE_COILS;
            //从内存中读取线圈
            if (MB_BitSetReset(pReqADU->Pdu.Value, hslave->Regedit.pCoilsBuffPtr, MB_PP_NTOHS(pReqADU->Pdu.StartAddress)) == MB_OK)
            {
                pRspADU->Pdu.StartAddress = pReqADU->Pdu.StartAddress;
                pRspADU->Pdu.Value = pReqADU->Pdu.Value;
                rspDataLen = 6;
                crc = MB_GenerateCRC16CheckCode(pRspBuf, rspDataLen);
                pRspADU->CRC = MB_PP_HTONS(crc);
               *pRspLen = rspDataLen + 2;
							 return MB_OK;
            }
            else
            {
                return MB_SLAVE_ExceptionRsp(hslave, pReqADU->Pdu.FunctionCode, 4, pRspBuf, pRspLen);
            }
        }
        else
        {
            return MB_SLAVE_ExceptionRsp(hslave, pReqADU->Pdu.FunctionCode, 2, pRspBuf, pRspLen);
        }
    }
    else
    {
        return MB_SLAVE_ExceptionRsp(hslave, pReqADU->Pdu.FunctionCode, 3, pRspBuf, pRspLen);
    }
}

/**
 * @brief 15(0x0F) 写多个线圈功能码 响应
 * @param hslave        从站指针
 * @param pSrc          需要解析的数据指针
 * @ret   MB_OK 成功 其它 出错
*/
MB_StatusTypeDef MB_COILS_WriteMultiple_Response(
    MB_SLAVE_HandleTypeDef *hslave,
    uint8_t *pReqBuf,
    uint8_t *pRspBuf,
    uint16_t *pRspLen)
{
    uint16_t rspDataLen = 0;
    uint16_t crc = 0;

    MB_WRITE_MULTIPLE_REQADU_HandleTypeDef *pReqADU = (MB_WRITE_MULTIPLE_REQADU_HandleTypeDef *)pReqBuf;
    MB_WRITE_MULTIPLE_RSPADU_HandleTypeDef *pRspADU = (MB_WRITE_MULTIPLE_RSPADU_HandleTypeDef *)pRspBuf;
    //判断值是不是 0X0000 / 0XFF00 (GB/T 1958.2.1 2008  第十九页)
    if (MB_PP_NTOHS(pReqADU->Pdu.Quantity) >= 0x0001 && MB_PP_NTOHS(pReqADU->Pdu.Quantity) <= 0x07B0)
    {
        //判断开始地址加上长度是不是在定义的寄存器范围内
        if (MB_PP_NTOHS(pReqADU->Pdu.StartAddress) + (MB_PP_NTOHS(pReqADU->Pdu.Quantity) / 8 + 1) < hslave->Regedit.CoilsBufSize)
        {
            //处理请求
            pRspADU->AdditionalAddress = hslave->SlaveID;
            pRspADU->Pdu.FunctionCode = MB_FUN_WRITE_MULTIPLE_COILS;
            //从内存中读取线圈
            if (MB_BitArraySetReset(
							pReqADU->Pdu.Data, 
							hslave->Regedit.pCoilsBuffPtr, 
						  MB_PP_NTOHS(pReqADU->Pdu.StartAddress),
						  MB_PP_NTOHS(pReqADU->Pdu.Quantity)
						  ) == MB_OK)
            {
                pRspADU->Pdu.StartAddress = pReqADU->Pdu.StartAddress;
                pRspADU->Pdu.Quantity = pReqADU->Pdu.Quantity;
                rspDataLen = 6;
                crc = MB_GenerateCRC16CheckCode(pRspBuf, rspDataLen);
                pRspADU->CRC = MB_PP_NTOHS(crc);
                *pRspLen = rspDataLen + 2;
							  return MB_OK;
            }
            else
            {
                return MB_SLAVE_ExceptionRsp(hslave, pReqADU->Pdu.FunctionCode, 4, pRspBuf, pRspLen);
            }
        }
        else
        {
            return MB_SLAVE_ExceptionRsp(hslave, pReqADU->Pdu.FunctionCode, 2, pRspBuf, pRspLen);
        }
    }
    else
    {
        return MB_SLAVE_ExceptionRsp(hslave, pReqADU->Pdu.FunctionCode, 3, pRspBuf, pRspLen);
    }
}
